package com.databus;

import java.util.ArrayList;

import com.google.protobuf.GeneratedMessage;
import com.databus.*;

public class SyncMessageArray {

	public SyncMessageArray(int nSize)
	{
		mSyncMsg = new ArrayList<SyncMessageItem>(nSize);
		for(int i = 0; i < nSize; i++)
		{
			mSyncMsg.add(new SyncMessageItem());
		}
	}

	public synchronized  FutureResponse<Object> RegistMsg(int serNum)
	{
		if(mSyncMsg.size() <= serNum || mSyncMsg.get(serNum).mUsed)
		{
			Log.error("Serial Num is used, num = " + serNum);
			return null;
		}
		SyncMessageItem item=mSyncMsg.get(serNum);
		item.mUsed = true;
		item.mRspMsg = null;
		FutureResponse<Object> future=new FutureResponse<Object>();
		future.setSerail(serNum);
		future.setSyncObj(this);
		item.future=future;
		return future;
	}

	public synchronized boolean RegistSyncMsg(int serNum)
	{
		if(mSyncMsg.size() <= serNum || mSyncMsg.get(serNum).mUsed)
		{
			Log.error("Serial Num is used, num = " + serNum);
			return false;
		}
		SyncMessageItem item=mSyncMsg.get(serNum);
		item.mUsed = true;
		item.mRspMsg = null;
		return true;
	}

	public boolean CopyMessageAndNotify(int serNum, Object msg)
	{
		if(mSyncMsg.size() <= serNum)
		{
			Log.error("serNum is out range, num = " + serNum);
			return false;
		}
		
		SyncMessageItem item = mSyncMsg.get(serNum);
		synchronized(item)
		{
			if(!item.mUsed)
			{
				Log.error("serNum is not used, num = " + serNum);
				return false;
			}
			item.mRspMsg = msg;
			if(item.future!=null)
				item.future.setValue(msg);
			item.notify();
		}
		return true;
	}
	
	public Object WaitForResponse(int serNum, long timeOut)
	{
		if(mSyncMsg.size() <= serNum)
		{
			Log.error("serNum is out range, num = " + serNum);
			return null;
		}

		Object msg = null;
		SyncMessageItem item = mSyncMsg.get(serNum);
		synchronized (item) 
		{
			if(!item.mUsed)
			{
				Log.error("serNum is not used, num = " + serNum);
				return null;
			}
			try {
				if(item.mRspMsg == null)
				{
					item.wait(timeOut);
				}
				msg = item.mRspMsg;
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				Log.error("Wait for response time out, serNum = " + serNum);
			}
			UnRegistSyncMsg(serNum);
		}
		
		return msg;
	}
	
	protected synchronized void UnRegistSyncMsg(int serNum)
	{
		if(mSyncMsg.size() <= serNum || !mSyncMsg.get(serNum).mUsed)
		{
			return;
		}
		mSyncMsg.get(serNum).mUsed = false;
		mSyncMsg.get(serNum).mRspMsg = null;
	}
	
	protected class SyncMessageItem
	{
		public Object mRspMsg = null;
		public FutureResponse<Object> future=null;
		public boolean mUsed;
	}
	
	private ArrayList<SyncMessageItem> mSyncMsg;
}
